package payment

//微信支付回调处理，处理微信支付通知并更新系统中的订单状态及相关数据
import (
	"cloud_android_backend/pkg/config"
	"cloud_android_backend/pkg/models/orders"
	"cloud_android_backend/pkg/models/products"
	"cloud_android_backend/pkg/models/resources"
	user "cloud_android_backend/pkg/models/users"
	"cloud_android_backend/pkg/modules/realphone"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/jinzhu/gorm"
	"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"modules.tenxcloud.com/common/composite"
	"strconv"
	"time"

	"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
)

const (
	WechatPayCallBackStateSuccess = "SUCCESS"
	WechatPayCallBackStateRefund  = "REFUND"
	WechatPayCallBackStateNotPay  = "NOTPAY"
	WechatPayCallBackStateClosed  = "CLOSED"
)

func WechatCallbackHandler(c *gin.Context) error {
	wechatPayConfig := config.Config.WechatPay
	//mchID := "1716855971"
	//mchCertSerialNumber := "7EA87FC59A92C7A44842A50D09A4BD4E6BDD7EC4"
	//apiV3Key := "hd6Tjdwqm28HBioSjd9wqermdfH0PlsL" // 微信商户平台上配置的API v3密钥
	//appID := "wxc2a222c61155056e"
	//var wechatpayPublicKeyID string = "PUB_KEY_ID_0117168559712025051400211938002002" // 微信支付公钥ID
	// 加载商户私钥
	//privateKey, err := utils.LoadPrivateKeyWithPath(wechatPayConfig.PrivateKeyPath) //"C:\\Users\\admin\\GolandProjects\\container_manager\\cert\\apiclient_key.pem"
	//if err != nil {
	//	log.Printf("load private key err: %v", err)
	//	return err
	//}
	wechatpayPublicKey, err := utils.LoadPublicKeyWithPath(wechatPayConfig.PublicKeyPath) //"C:\\Users\\admin\\GolandProjects\\container_manager\\cert\\pub_key.pem"
	if err != nil {
		return err
	}

	// 初始化 notify.Handler
	handler := notify.NewNotifyHandler(
		wechatPayConfig.ApiV3Key,
		verifiers.NewSHA256WithRSAPubkeyVerifier(wechatPayConfig.PublicKeyID, *wechatpayPublicKey))
	transaction := new(payments.Transaction)
	notifyReq, err := handler.ParseNotifyRequest(context.Background(), c.Request, transaction)
	// 如果验签未通过，或者解密失败
	if err != nil {
		fmt.Println(err)
		return err
	}
	transactionJson, err := json.Marshal(transaction)
	if err != nil {
		fmt.Printf("marshall transaction json failed:%v\n", err)
		//return err
	}
	fmt.Printf("微信支付回调返回transaction：%s\n", string(transactionJson))

	// 处理通知内容
	fmt.Println(notifyReq.Summary)
	fmt.Println(transaction.TransactionId)
	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Errorf("获取数据库连接失败: %v", err)
		return err
	}

	TradeNo := transaction.OutTradeNo
	orderModel := orders.Orders{TradeNo: *TradeNo}
	if err := orderModel.FindByTradeNo(db); err != nil {
		glog.Errorf("查询订单失败: %v", err)
		return err
	}
	//使用数据库事务处理？
	err = db.Transaction(func(tx *gorm.DB) error {
		switch *transaction.TradeState {
		case WechatPayCallBackStateSuccess:
			orderModel.Status = int(orders.OrderStatus_Success)
		case WechatPayCallBackStateClosed:
			orderModel.Status = int(orders.OrderStatus_Cancel)
		case WechatPayCallBackStateNotPay:
			orderModel.Status = int(orders.OrderStatus_Pending)
		}
		//解析支付时间并更新
		t, err := time.Parse(time.RFC3339, *transaction.SuccessTime)
		if err != nil {
			fmt.Println("解析失败:", err)

		}
		orderModel.PayTime = t
		orderModel.ActualAmount = float64(*transaction.Amount.PayerTotal) / 100 //更新订单实际金额
		orderModel.CallbackTime = time.Now()
		orderModel.CallbackContent = string(transactionJson)
		orderModel.TransactionId = *transaction.TransactionId
		//将更新后的订单信息保存到数据库中
		err = orderModel.Update(db)
		if err != nil {
			glog.Errorf("更新订单失败: %v", err)
			return err
		}
		paymentTransaction := &orders.PaymentTransactions{
			OrderId:       orderModel.Id,
			TransactionId: *transaction.TransactionId,
			PaymentSource: "wechat",
			Amount:        orderModel.Amount,
			OrderType:     int(orderModel.OrderType),
			CallbackTime:  t,
			CallbackData:  transaction.String(),
			UserId:        orderModel.UserId,
			CreatedAt:     time.Now(),
			TradeNo:       orderModel.TradeNo,
			//UpdatedAt: time.Now(),
		}
		if err := paymentTransaction.Create(db); err != nil {
			glog.Errorf("create payment transaction failed:err %v", err)
			return err
		}
		switch orderModel.OrderType {
		case int(orders.OrderTypeRecharge): //充值
			userModel := user.User{UserID: orderModel.UserId}
			err = userModel.IncreseBalance(db, orderModel.UserId, orderModel.Amount)
			if err != nil {
				glog.Errorf("increse balance failed:err %v", err)
				return err
			}
			accountTransactionModel := orders.AccountTransactions{
				UserId:      orderModel.UserId, //UserId是充值订单所属的用户ID
				Amount:      orderModel.Amount,
				Description: "充值",
				Type:        orders.AccountTransactionsTypeRecharge,
				CreatedAt:   time.Now(),
			}
			err = accountTransactionModel.Create(db)
			if err != nil {
				glog.Errorf("create account transaction failed:err %v", err)
				return err
			}
		case int(orders.OrderTypeInstance): //购买云手机，设置实例的使用时间和过期时间，并启动实例连接操作
			//创建一个 products.ProductPackages 类型的实例 packageInfo，并设置其 Id 为订单中指定的产品套餐 ID。
			packageInfo := products.ProductPackages{Id: orderModel.PackageId}
			err = packageInfo.GetById(db)
			if err != nil {
				glog.Errorf("get product package info failed:err %v", err)
				return err
			}
			instanceModel := resources.InstanceUses{OrderId: orderModel.Id}
			instanceList, err := instanceModel.GetListByOrderId(tx)
			if err != nil {
				glog.Errorf("get instance use list failed:err %v", err)
				return err
			}
			productModel := products.Products{Id: packageInfo.ProductId}
			err = productModel.GetById(tx)
			if err != nil {
				glog.Errorf("get product info failed:err %v", err)
				return err
			}
			for _, instance := range instanceList {
				instance.Status = int(resources.InstanceUseStatusUsing)
				instance.StartTime = time.Now()
				//设置设备过期时间
				instance.ExpireTime = time.Now().AddDate(0, 0, packageInfo.Duration)
				instance.InstanceName = "云机" + strconv.FormatInt(instance.Id, 10)
				err = instance.Update(tx)
				if err != nil {
					glog.Errorf("update instance use failed:err %v", err)
					return err
				}
				if productModel.Type == 1 {
					go func(id int64) {
						if err := realphone.EasyToRecreateNewInstance(id, instanceModel.UserId); err != nil {
							glog.Error(err)
						}
					}(instance.Id)
				} else {
					instancesModel := resources.Instances{Id: instance.InstanceId}
					err = instancesModel.GetById(tx)
					if err != nil {
						glog.Errorf("get instance failed:err %v", err)
					}
					if instancesModel.AdiTemplateId == 0 {
						instancesModel.AdiTemplateId = 36
					}
					go func(id int64) {
						if err := realphone.ChangeRealPhoneModelAndClearData(id, instancesModel.AdiTemplateId, orderModel.UserId); err != nil {
							glog.Error(err)
						}
					}(instance.Id)
				}
			}
		case int(orders.OrderTypeRenew):
			packageInfo := products.ProductPackages{Id: orderModel.PackageId}
			err = packageInfo.GetById(db)
			if err != nil {
				glog.Errorf("get product package info failed:err %v", err)
				return err
			}
			instanceModel := resources.InstanceUses{OrderId: orderModel.Id}
			instanceList, err := instanceModel.GetListByOrderId(tx)
			if err != nil {
				glog.Errorf("get instance use list failed:err %v", err)
				return err
			}
			for _, instance := range instanceList {
				instanceModel := &instance
				instanceModel.Status = int(resources.InstanceUseStatusUsing)
				err = instanceModel.Update(tx)
				if err != nil {
					glog.Errorf("update instance use failed:err %v", err)
					return err
				}
				if instance.PrewInstanceId > 0 {
					prewInstanceModel := resources.InstanceUses{Id: instance.PrewInstanceId}
					err = prewInstanceModel.UpdatePartFields(tx, map[string]interface{}{"status": int(resources.InstanceUseStatusExpired)})
					if err != nil {
						glog.Errorf("update instance use failed:err %v", err)
						return err
					}
				}
			}

		}
		return nil
	})
	if err != nil {
		glog.Errorf("transaction failed:err %v", err)
		return err
	}
	// 返回应答
	//	w.WriteHeader(http.StatusOK)
	//w.Write([]byte(`{"code":"SUCCESS","message":"成功"}`))
	//c.JSON(http.StatusOK, gin.H{"code": "SUCCESS", "message": "成功"})
	return nil
}
